//
//  FolderViewController.m
//  iGSS
//
//  Copyright 2010 Electronic Business Systems Ltd.
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//

#import "FolderViewController.h"

#import "MetaViewController.h"
#import "ImageViewController.h"
#import "TextViewController.h"
#import "HTMLViewController.h"
#import "GenericViewController.h"

#import "AddFolderController.h"
#import "AddPhotoController.h"
#import "AddNoteController.h"

#import "FormattingUtilities.h"
#import "GSSCommunicator.h"
#import "GSSOperation.h"
#import "GSSObject.h"
#import "GSSQuery.h"
#import "MIME.h"

#define SHOW_STALE_INTERVAL 300
#define DENY_SIZE_THRESHOLD  50000000LL

@implementation FolderViewController

@synthesize query;
@synthesize children;

@synthesize loading;

@synthesize showsAddButton;
@synthesize showsDeleted;

@synthesize footerTopLabel;
@synthesize footerBottomLabel;

@synthesize toolbar;
@synthesize toolbarLabel;
@synthesize activityIndicator;


//MARK: -

- (id)initWithGSSObject:(GSSObject *)anObject {
    if (self = [super initWithNibName:@"FolderViewController" bundle:nil]) {
        object = [anObject retain];
        showsAddButton = YES;
    }
    return self;
}

- (void)dealloc {
    self.query = nil;
    [object release];
    
    [children release];
    [dateFormatter release];
    
    [footerTopLabel release];
    [footerBottomLabel release];
    
    [toolbar release];
    [toolbarLabel release];
    [activityIndicator release];

    [super dealloc];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)anObject change:(NSDictionary *)change context:(void *)context {
    if (anObject == self.query) {
        [self.searchDisplayController.searchResultsTableView reloadData];
        return;
    }
    
    [self stopActivity];

    if ([keyPath isEqualToString:@"meta"]) {
        [self reloadData];
    } else if ([keyPath isEqualToString:@"children"]) {
        self.children = nil;
    } else if ([keyPath isEqualToString:@"childrenUpdated"]) {
        [self reloadData];
    } else if ([keyPath isEqualToString:@"fetchDate"]) {
        [self reloadToolbar];
    } else if ([keyPath isEqualToString:@"error"]) {
        switch (object.error) {
            case GSSOperationErrorAuthentication:
                [self authenticate];
                break;
            default:
                self.toolbarLabel.text = LocalizedString(@"Network error");
                break;
        }
    }
}


//MARK: -
//MARK: Properties

- (void)setQuery:(GSSQuery *)aQuery {
    if (aQuery == query)
        return;
    
    [query removeObserver:self forKeyPath:@"children"];
    [query removeObserver:self forKeyPath:@"childrenUpdated"];   
    
    [query release];
    query = [aQuery retain];
    
    [query addObserver:self forKeyPath:@"children" options:0 context:NULL];
    [query addObserver:self forKeyPath:@"childrenUpdated" options:0 context:NULL];
}

- (NSArray *)children {
    if (!children) {
        if (showsDeleted) {
            children = [[object.children sortedArrayUsingSelector:@selector(compare:)] retain];
        } else {
            NSPredicate *predicate = [NSPredicate predicateWithFormat:@"deleted = %@",
                                      [NSNumber numberWithBool:NO]];
            NSArray *filtered = [object.children filteredArrayUsingPredicate:predicate];
            children = [[filtered sortedArrayUsingSelector:@selector(compare:)] retain];
        }
    }
    return children;
}

- (NSDateFormatter *)dateFormatter {
    if (!dateFormatter) {
        dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:LocalizedString(@"{Date format}")];
    }
    return dateFormatter;
}


//MARK: -
//MARK: UIViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.title = object.name;
    self.tableView.tableHeaderView = self.searchDisplayController.searchBar;
    
    if (self.showsAddButton) {
        UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addPressed)];
        self.navigationItem.rightBarButtonItem = addButton;
        [addButton release];
    }
    
    [self stopActivity];    // Initialize the toolbar
    
    [self.tableView reloadData];
    if ([self.children count]) {
        [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
                              atScrollPosition:UITableViewScrollPositionTop
                                      animated:NO];        
    }
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.navigationController setToolbarHidden:NO animated:NO];

    [object addObserver:self forKeyPath:@"meta" options:0 context:NULL];
    [object addObserver:self forKeyPath:@"children" options:0 context:NULL];
    [object addObserver:self forKeyPath:@"childrenUpdated" options:0 context:NULL];
    [object addObserver:self forKeyPath:@"fetchDate" options:0 context:NULL];
    [object addObserver:self forKeyPath:@"error" options:0 context:NULL];

    GSSCommunicator *communicator = [GSSCommunicator defaultCommunicator];
    
    if (!communicator.username || !communicator.token) {        
        [self reloadToolbar];
        [self authenticate];
    } else if (object.isEmpty || object.isStale) {
        [communicator updateMetaOfObject:object];
        [self startActivity];
    } else {
        [self reloadData];
        [self reloadToolbar];
    }
    
    [object updateMetaAccessDate];
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    
    self.children = nil;

    [object removeObserver:self forKeyPath:@"meta"];
    [object removeObserver:self forKeyPath:@"children"];
    [object removeObserver:self forKeyPath:@"childrenUpdated"];
    [object removeObserver:self forKeyPath:@"fetchDate"];
    [object removeObserver:self forKeyPath:@"error"];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
	return YES;
}


//MARK: -
//MARK: UITableViewDataSource

- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
    if (aTableView == self.tableView)
        return [self.children count];
    else
        return [self.query.children count];
}

- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"FolderViewCell";
    
    UITableViewCell *cell = [aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [[[UITableViewCell alloc]
                 initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
        cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
        cell.textLabel.font = [UIFont boldSystemFontOfSize:14];
        cell.textLabel.lineBreakMode = UILineBreakModeMiddleTruncation;
        cell.detailTextLabel.font = [UIFont systemFontOfSize:12];
    }
    
    GSSObject *child;
    if (aTableView == self.tableView)
        child = [self.children objectAtIndex:indexPath.row];
    else
        child = [self.query.children objectAtIndex:indexPath.row];
    
    if (child.isStale || child.isPartial)
        [[GSSCommunicator defaultCommunicator] prefetchObject:child];
        
    cell.imageView.image = child.icon;
    cell.textLabel.text = child.name;
    
    if (-[child.fetchDate timeIntervalSinceNow] > SHOW_STALE_INTERVAL)
        cell.textLabel.textColor = [UIColor darkGrayColor];
    else
        cell.textLabel.textColor = [UIColor blackColor];
    
    if (child.type == GSSObjectTypeFile) {
        if (![MIME canDisplayType:child.content] || child.size > DENY_SIZE_THRESHOLD)
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
        else
            cell.selectionStyle = UITableViewCellSelectionStyleBlue;
        
        if (child.uploading) {
            cell.detailTextLabel.text = LocalizedString(@"Uploading...");
        } else if (child.versioned) {
            cell.detailTextLabel.text = [NSString stringWithFormat:
                                         @"%@ • %@ • %@",
                                         [self.dateFormatter stringFromDate:child.modificationDate],
                                         [FormattingUtilities byteStringForSize:child.size],
                                         [NSString stringWithFormat:
                                          LocalizedString(@"{Version}"),
                                          child.version]];            
        } else if (child.modificationDate) {
            cell.detailTextLabel.text = [NSString stringWithFormat:
                                         @"%@ • %@",
                                         [self.dateFormatter stringFromDate:child.modificationDate],
                                         [FormattingUtilities byteStringForSize:child.size]];
        } else {
            cell.detailTextLabel.text = nil;
        }
    
    } else {
        cell.selectionStyle = UITableViewCellSelectionStyleBlue;
        
        if (child.uploading) {
            cell.detailTextLabel.text = LocalizedString(@"Creating...");
        } else if (!child.isPartial) {
            NSInteger count = [child.children count];
            NSString *files = (count == 1) ? LocalizedString(@"file") : LocalizedString(@"files");
            cell.detailTextLabel.text = [NSString stringWithFormat:@"%d %@", count, files];            
        } else {
            cell.detailTextLabel.text = nil;
        }
    }
    
    return cell;
}


//MARK: -
//MARK: UITableViewDelegate

- (NSIndexPath *)tableView:(UITableView *)aTableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    GSSObject *child;
    if (aTableView == self.tableView)
        child = [self.children objectAtIndex:indexPath.row];
    else
        child = [self.query.children objectAtIndex:indexPath.row];

    if (child.type != GSSObjectTypeFile)
        return indexPath;
    
    if (![MIME canDisplayType:child.content] || child.size > DENY_SIZE_THRESHOLD)
        return nil;
    else
        return indexPath;    
}

- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    GSSObject *child;
    if (aTableView == self.tableView)
        child = [self.children objectAtIndex:indexPath.row];
    else
        child = [self.query.children objectAtIndex:indexPath.row];
    
    UIViewController *viewController;
    
    if (child.type == GSSObjectTypeFile) {
        NSString *mimeType = child.content;
        
        if ([mimeType hasPrefix:@"image/"])
            viewController = [[ImageViewController alloc] initWithFile:child inFolder:object];
        else if ([mimeType isEqualToString:@"text/plain"])
            viewController = [[TextViewController alloc] initWithFile:child inFolder:object];
        else if ([mimeType isEqualToString:@"text/html"])
            viewController = [[HTMLViewController alloc] initWithFile:child inFolder:object];
        else
            viewController = [[GenericViewController alloc] initWithFile:child inFolder:object];
    } else {
        viewController = [[FolderViewController alloc] initWithGSSObject:child];
    }
    
    [self.navigationController pushViewController:viewController animated:YES];
    [viewController release];
}

- (void)tableView:(UITableView *)aTableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
    GSSObject *child;
    if (aTableView == self.tableView)
        child = [self.children objectAtIndex:indexPath.row];
    else
        child = [self.query.children objectAtIndex:indexPath.row];
    
    MetaViewController *metaViewController = [[MetaViewController alloc] initWithGSSObject:child];
    [self.navigationController pushViewController:metaViewController animated:YES];
    [metaViewController release];
}


//MARK: -
//MARK: UISearchDisplayDelegate

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
    self.query = [[GSSCommunicator defaultCommunicator] searchFiles:searchString];
    return NO;
}


//MARK: -
//MARK: UIAlertViewDelegate

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    [alertView release];
    if (buttonIndex == 1) {
        NSURL *url = [[GSSCommunicator defaultCommunicator] loginURL];
        NSLog(@"OPEN %@", url);
        [[UIApplication sharedApplication] openURL:url];
    }
}


//MARK: -
//MARK: UIActionSheetDelegate

- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
    UIViewController *viewController;
    
    switch (buttonIndex) {
        case 0:
            viewController = [[AddFolderController alloc] initWithFolder:object];            
            break;
        
        case 1:
            viewController = [[AddPhotoController alloc] initWithFolder:object];
            break;
            
        case 2:
            viewController = [[AddNoteController alloc] initWithFolder:object];
            break;
        
        default:
            NSLog(@"Unhandled button selected");
            return;
    }
    
    [self presentModalViewController:viewController animated:YES];
    [viewController release];
    [actionSheet release];
}


//MARK: -
//MARK: PhotoViewControllerDelegated

- (void)photoUploadFinished {
    [self dismissModalViewControllerAnimated:YES];
    [self reloadData];
}

//MARK: -
//MARK: IBActions

- (IBAction)refreshPressed {
    [[GSSCommunicator defaultCommunicator] updateMetaOfObject:object];
    [self startActivity];
}

- (IBAction)homePressed {
    [self.navigationController popToRootViewControllerAnimated:YES];
}

- (IBAction)addPressed {
    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil
															 delegate:self
													cancelButtonTitle:LocalizedString(@"Cancel")
											   destructiveButtonTitle:nil
													otherButtonTitles:LocalizedString(@"Add folder"),
                                                                      LocalizedString(@"Add image"),
                                                                      LocalizedString(@"Add note"),
                                                                      nil];
	actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
	[actionSheet showInView:[[UIApplication sharedApplication] keyWindow]];
}

//MARK: -

- (void)authenticate {
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:LocalizedString(@"Authentication needed")
                                                        message:LocalizedString(@"{app will quit}")
                                                       delegate:self
                                              cancelButtonTitle:LocalizedString(@"Cancel")
                                              otherButtonTitles:LocalizedString(@"Authenticate"), nil];
    [alertView show];
}

- (void)reloadData {    
    NSUInteger count = [self.children count];
    
    if (count) {
        self.footerTopLabel.text = [NSString stringWithFormat:
                                    LocalizedString(@"{Bytes used}"),
                                    [FormattingUtilities byteStringForSize:object.size],
                                    count];
    } else {
        self.footerTopLabel.text = LocalizedString(@"Empty folder");
    }
    
    NSDate *date = object.modificationDate;
    if (date) {
        self.footerBottomLabel.text = [NSString stringWithFormat:
                                       LocalizedString(@"{Folder modified}"),
                                       [self.dateFormatter stringFromDate:object.modificationDate]];
    } else {
        self.footerBottomLabel.text = nil;
    }
        
    [self.tableView reloadData];
}

- (void)reloadToolbar {
    GSSCommunicator *communicator = [GSSCommunicator defaultCommunicator];
    if (!communicator.username || !communicator.token) {
        // Disable Refresh
        UIBarButtonItem *refresh = [[UIBarButtonItem alloc]
                                    initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
                                    target:nil
                                    action:nil];
        refresh.enabled = NO;
        self.toolbarItems = [[NSArray arrayWithObject:refresh]
                             arrayByAddingObjectsFromArray:self.toolbar.items];
        [refresh release];
        
        self.toolbarLabel.text = LocalizedString(@"You are logged out");
        return;
    }
    
    NSDate *fetchDate = object.fetchDate;
    
    if (fetchDate) {
        self.toolbarLabel.text = [NSString stringWithFormat:
                                  LocalizedString(@"{Last update}"),
                                  [self.dateFormatter stringFromDate:fetchDate]];
    } else {
        self.toolbarLabel.text = nil;
    }        
}

- (void)startActivity {
    self.loading = YES;
    UIBarButtonItem *refresh = [[UIBarButtonItem alloc] initWithCustomView:self.activityIndicator];
    self.toolbarItems = [[NSArray arrayWithObject:refresh]
                         arrayByAddingObjectsFromArray:self.toolbar.items];
    self.toolbarLabel.text = LocalizedString(@"Loading...");
    [refresh release];
}

- (void)stopActivity {
    self.loading = NO;
    UIBarButtonItem *refresh = [[UIBarButtonItem alloc]
                                initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh
                                                     target:self
                                                     action:@selector(refreshPressed)];
    self.toolbarItems = [[NSArray arrayWithObject:refresh]
                         arrayByAddingObjectsFromArray:self.toolbar.items];
    [self reloadToolbar];
    [refresh release];
}

@end

